package com.cc.utils;

import com.cc.dto.TreeNodeData;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * Created with IntelliJ IDEA.
 *
 * @author : c.c
 * @Date: 2022/6/27
 * @Time: 16:26
 * @Description: 树 继承泛型TreeNodeData
  */
@Getter
public class TreeNode<T extends TreeNodeData> {

  private final static Integer ROOT_LEVEL =  1;
  /**
   * @author: C.c
   * @date: 2022-06-27 16:31
   * @description:父级节点
  **/
  private final TreeNode<T> parent;

  /**
   * @author: C.c
   * @date: 2022-06-27 16:32
   * @description: 子集集合节点
  **/
  private final List<TreeNode<T>> childrenList = new ArrayList<TreeNode<T>>();

  /**
   * @author: C.c
   * @date: 2022-06-27 16:32
   * @description: 当前节点
   **/
  private final T data;

  /**
   * @author: C.c
   * @date: 2022-06-27 16:32
   * @description: 当前节点层级
   **/
  private final int level;

  public TreeNode(TreeNode<T> parent, T data, int level) {
    this.parent = parent;
    this.data = data;
    this.level = level;
  }

  @Override
  public String toString() {
    return "TreeNode{children=" + childrenList + ", data=" + data + ", level=" + level + '}';
  }

  /**
   * 构建树形节点集合
   *
   * @param sourceData 支持构建的数据结合
   * @return 树形节点集合
   */
  public static <T extends TreeNodeData> List<TreeNode<T>> buildListTree(List<T> sourceData){

    //父节点
    final List<T> rootList = new ArrayList<T>();
    //获取子节点
    Map<Object, List<T>> childMap = sourceData.stream()
      .filter(childOrParent -> {
          if (childOrParent.root()) {
            //说明是父节点
            rootList.add(childOrParent);
            return false;
          }
          return StringUtils.isNotBlank(childOrParent.parentId().toString());
        }
      )
      //根据父类id分组
      .collect(Collectors.groupingBy(TreeNodeData::parentId));

    //把数组rootlist设置root节点
    List<TreeNode<T>> treeList = rootList.stream()
      .map(root -> new TreeNode<>(null, root, 1))
      .collect(Collectors.toList());
    //设置子节点
    treeList.forEach(root -> {
      AddChild(childMap, root);
    });
    return treeList;
  }

  /**
   * @author: C.c
   * @date: 2022-06-28 08:30
   * @description: 自定义根节点，构建树
   * @param root 根节点
   * @param sourceData 子节点数据
   * @return TreeNode<T> T为继承TreeNodeData这个类的相关类
  **/
  public static <T extends TreeNodeData> TreeNode<T> buildSingleTree(T root,List<T> sourceData){
    //获取子节点
    Map<Object, List<T>> childMap = sourceData.stream()
      .collect(Collectors.groupingBy(TreeNodeData::parentId));
    //构建根节点
    TreeNode<T> treeSingle = new TreeNode<T>(null, root, ROOT_LEVEL);

    //添加子节点
    AddChild(childMap,treeSingle);
    return treeSingle;
  }

  /**
   * @author: C.c
   * @date: 2022-06-28 08:49
   * @description: 使用广度优先查找遍历 广度优先 使用队列 因为队列先进先出。即访问一个后马上访问出列，访问下一个
   * @param consumer  `Consumer` 函数式接口的函数方法，传入一个任意类型，无返回值，可以用于 Lambda 表达式和方法引用。
  **/
  public void  bfsEach(Consumer<TreeNode<T>> consumer){
    //双向队列 this指的是外引用时传递进来的参数
    ArrayDeque<TreeNode<T>> nodeQueue = new ArrayDeque<>(Collections.singletonList(this));
    while (!nodeQueue.isEmpty()){
      //出队列
      TreeNode<T> tTreeNode = nodeQueue.pop();
      //lamda表达式，执行外部方法
      consumer.accept(tTreeNode);
      //得到子集
      List<TreeNode<T>> childrenList = tTreeNode.getChildrenList();
      if (childrenList!=null&&!childrenList.isEmpty()){
        //说明存在子集，入队列
        nodeQueue.addAll(childrenList);
      }
    }
  }

  /**
   * @author: C.c
   * @date: 2022-06-28 09:52
   * @description: 深度遍历
   * @param consumer
   * @return
  **/
  public void dfsEach(Consumer<TreeNode<T>> consumer){
    //声明一个栈
    Stack<TreeNode<T>> nodeStack = new Stack<>();
    //添加外部集合
    for (TreeNode<T> node : Collections.singletonList(this)) {
      nodeStack.push(node);
      while (!nodeStack.isEmpty()){
        //出栈
        TreeNode<T> pop = nodeStack.pop();
        //交给外部处理
        consumer.accept(pop);
        //得到子集
        List<TreeNode<T>> childrenList = pop.getChildrenList();
        if (childrenList!=null&&!childrenList.isEmpty()){
          childrenList.forEach(nodeStack::push);
        }
      }
    }
  }



    /**
     * @author: C.c
     * @date: 2022-06-28 08:28
     * @description: 添加子节点
    **/
  private static <T extends TreeNodeData> void AddChild(Map<Object, List<T>> childMap, TreeNode<T> root) {
    //因为是根据parentId分的类，所以当root.id.get()的值肯定就是父类的id，既然如此map k值为父类id 那么v肯定就是其子类
    List<T> childDate = childMap.get(root.data.id());
    //判断是否存在
    if (childDate==null||childDate.size()<1){
      return;
    }
    //遍历childDate
    for (T t : childDate) {
      //新建子类
      TreeNode<T> childNode = new TreeNode<>(root, t, root.level + 1);
      //添加到父类的子类去
      root.childrenList.add(childNode);
      //递归继续调用
      AddChild(childMap,childNode);
    }
  }


}
